#include "StdAfx.h"
#include ".\geneset.h"


void GeneSet::initGenes( ){
		initBaseTypes( );
		Arity1Function		= new ArrowType(*Ty_Number, 	*Ty_Number);
		Arity2Function		= new ArrowType(*Ty_Number, *Arity1Function);
		Predicate			= new ArrowType(*Ty_Number, *Ty_Boolean);
		BinaryRelation		= new ArrowType(*Ty_Number, *Predicate);
		initNumbers();
		initBooleans();
		initBooleanOperators();
		initBinaryFunctions( );
	}
GeneSet::GeneSet(void)
	{
		
	}

GeneSet::~GeneSet(void)
	{
		delete Arity1Function;
		delete Arity2Function;
		delete Predicate;
		delete BinaryRelation;
		Constants.clear( );
	}

void GeneSet::initNumbers(){
	size_t size = 10;
	char c[2] = "0";
	for(size_t i=0; i<size; i++){
		FreeTermVariable* NewConstant = new FreeTermVariable(*Ty_Number, c);
		const Token* ToPtr = EvaluatingTermSet::insert(*NewConstant);
		SemanticEvaluation SE;
		SE.second = new F<double>(i);
		setValue( ToPtr, SE ); 
		Constants.push_back( ToPtr );
		this->setAsPrimitive( *ToPtr );
		delete NewConstant;
		c[0]  += 1;
		}

	FreeTermVariable* Variable = new FreeTermVariable(*Ty_Number, "Data Point");
	Var1 = EvaluatingTermSet::insert(*Variable);
	this->setAsPrimitive( *Var1 );
	delete Variable;
	}

void GeneSet::initBinaryFunctions( ){
		
	FreeTermVariable* PlusPtr = new FreeTermVariable(*Arity2Function, "+");
	Te_Plus = EvaluatingTermSet::insert(*PlusPtr);
	delete PlusPtr;
	Primitives.push_back( Te_Plus );

	FreeTermVariable* MultPtr = new FreeTermVariable(*Arity2Function, "*");
	Te_Mult = EvaluatingTermSet::insert(*MultPtr);
	delete MultPtr;
	Primitives.push_back( Te_Mult );

	FreeTermVariable* MinPtr = new FreeTermVariable(*Arity2Function, "-");
	Te_Minus = EvaluatingTermSet::insert(*MinPtr);
	delete MinPtr;
	Primitives.push_back( Te_Minus );

	FreeTermVariable* DivPtr = new FreeTermVariable(*Arity2Function, "/");
	Te_Div = EvaluatingTermSet::insert(*DivPtr);
	delete DivPtr;
	Primitives.push_back( Te_Div );

	FreeTermVariable* GtPtr = new FreeTermVariable(*BinaryRelation, ">");
	Te_Gt = EvaluatingTermSet::insert(*GtPtr);
	delete GtPtr;
	Primitives.push_back( Te_Gt );

}



Term* GeneSet::preEval( const ApplicationTerm& AT ) const{
	const ApplicationTerm* AppTPtr = &AT;
	while((!(isDefinedOp(*AppTPtr))) &&
			(AppTPtr->getLeft( ).isApplicationTerm( ))){
				AppTPtr =	&(_APPLICATIONTERM(AppTPtr->getLeft( )));
				}
	
		if(isDefinedOp(*AppTPtr)){
			SemanticEvaluation AppTPtrEvaluation = evalDefinedOp(*AppTPtr);
			if(AppTPtrEvaluation.first){
					Token* Temp = (AT.replaceAll(*AppTPtr, *AppTPtrEvaluation.first));
					Term* Res = _TERM(*Temp).normalized( );
					delete Temp;
					return Res;
				}
			}

	return NULL;
	}




SemanticEvaluation* GeneSet::evalDefinedOp(const ApplicationTerm& AT) const{
	const  Term& Left 	= AT.getLeft( );
	const Token& Right	= AT.getRight( );
	if(Left.isApplicationTerm( )){
		const Token& op			= _APPLICATIONTERM( Left ).getLeft( );
		const Token& leftArg	= _APPLICATIONTERM( Left ).getRight( );
		if(op == ( *Te_Plus )){
					SemanticEvaluation* SELeft    = eval( &leftArg ) ;
					SemanticEvaluation* SERight  = eval( &Right );
					SemanticEvaluation* SERes  = SELeft->SemanticPlus( SERight );
					delete SELeft;
					delete SERight;
					return SERes;
			}
		if(op == ( *Te_Mult)) {
				SemanticEvaluation* SELeft    = eval( &leftArg ) ;
				SemanticEvaluation* SERight  = eval( &Right );
				SemanticEvaluation* SERes  = SELeft->SemanticMult( SERight );
				delete SELeft;
				delete SERight;
				return SERes;
			}
		if(op == ( *Te_Div)) 	{
			SemanticEvaluation* SELeft		= eval( &leftArg ) ;
			SemanticEvaluation* SERight	= eval( &Right );
			SemanticEvaluation* SERes		= SELeft->SemanticDiv( SERight );
			delete SELeft;
			delete SERight;
			return SERes;
			}
		if(op == ( *Te_Minus)){
			SemanticEvaluation* SELeft    = eval( &leftArg ) ;
			SemanticEvaluation* SERight  = eval( &Right );
			SemanticEvaluation* SERes  = SELeft->SemanticMinus( SERight );
			delete SELeft;
			delete SERight;
			return SERes;
			}
		if(op == ( *Te_Gt)){
			SemanticEvaluation* SELeft    = eval( &leftArg ) ;
			SemanticEvaluation* SERight  = eval( &Right );
			SemanticEvaluation* SERes  = SELeft->SemanticGt( SERight );
			delete SELeft;
			delete SERight;
			return SERes;
			}

		}
	return NULL;
}


const SemanticEvaluation* GeneSet::getValue (const Term* Ter) const{
	return EvaluatingTermSet::getValue( Ter );
	}


SemanticEvaluation* GeneSet::eval(const Token* ToPtr) const{
	if(ToPtr->isTerm( )){												
		Term* TerPtr = _TERM(*ToPtr).normalized( );
		const SemanticEvaluation* SE =  getValue( TerPtr );
		if(SE){
			delete TerPtr;
			return SemanticEvaluation( );
			}
		if(TerPtr->isApplicationTerm( )){
			SemanticEvaluation* DefinedOpRes = evalDefinedOp(_APPLICATIONTERM( *TerPtr));
			if( DefinedOpRes ) return DefinedOpRes;
			Term* Simplified = preEval(AppTer);
			if(Simplified){	
				delete TerPtr;		
				SemanticEvaluation Res( eval(Simplified) );
				delete Simplified;
				return Res;
				}
			SemanticEvaluation SELeft(eval(&(AppTer.getLeft( ))));
			if(SELeft.first){
				ApplicationTerm* NewTerPtr = new ApplicationTerm(_TERM(*(SELeft.first)), AppTer.getRight( ));
				if(ToPtr->operator ==(*NewTerPtr))  throw string("Unable to evaluate");
				SemanticEvaluation Res( eval(NewTerPtr ));
				if(!(Res.first || Res.second)) {
					Res.first=NewTerPtr;	
					}
				else {
					delete NewTerPtr;
					}
				delete TerPtr;						
				return Res;
				}
			}	  
		delete TerPtr;
		}
	
	return SemanticEvaluation( );
	}


const Token* GeneSet::insert(Token::const_reference To){
	SemanticEvaluation SE(eval(&To));
	if(SE.first){
		return  EvaluatingTermSet::insert(*(SE.first));
		}	
	const Token* ToPtr = EvaluatingTermSet::insert(To);
	if(ToPtr) this->setValue(ToPtr, SE);
	return ToPtr;
	}

bool NoAbstractionGeneSet::isDefinedOp( const ApplicationTerm& AT) const{
	const Token* op = AT.caar( );
	if(op){
		if(op->operator==( *Te_Or)) 	return true;
		if(op->operator==( *Te_And)) 	return true;
		}
	op = AT.car( );
	if(op->operator==( *Te_Not)) return true;
	return GeneSet::isDefinedOp(AT);
	}

void NoAbstractionGeneSet::initBaseTypes( void ){
	FreeTypeVariable* NumType = new FreeTypeVariable("D");
	FreeTypeVariable* BoolType = new FreeTypeVariable("Boolean");

	Ty_Number		= static_cast<const Type*>(TermSet::insert( *NumType ));
	Ty_Boolean		= static_cast<const Type*>(TermSet::insert( *BoolType ));

	delete NumType;
	delete BoolType;
	}
void NoAbstractionGeneSet::initBooleans( void ){
	 FreeTermVariable* Te_TrueTemp = new FreeTermVariable(*Ty_Boolean, "True");	
	 Te_True = EvaluatingTermSet::insert(*Te_TrueTemp);
	 SemanticEvaluation SE;
	 SE.second = new F<double>(1.0F);
	 setValue( Te_True, SE ); 
	 this->setAsPrimitive( *Te_True );
	 delete Te_TrueTemp;	

	 FreeTermVariable* Te_FalseTemp = new FreeTermVariable(*Ty_Boolean, "False");
	 Te_False = EvaluatingTermSet::insert(*Te_FalseTemp);
	 SemanticEvaluation SE2;
	 SE2.second = new F<double>(0.0F);
	 setValue( Te_False, SE2 ); 
	 this->setAsPrimitive( *Te_False );
	 delete Te_FalseTemp;	

	 ArrowType*  UniBool		= new ArrowType(*Ty_Boolean, *Ty_Boolean);
	 ArrowType*  BiBool			= new ArrowType(*Ty_Boolean, *UniBool);
	 ArrowType*  Ty_ifBool		= new ArrowType(*Ty_Boolean, *BiBool);
	 FreeTermVariable* Te_ifBoolTemp = new FreeTermVariable (*Ty_ifBool	, "ifBool");	
	 Te_ifBool = EvaluatingTermSet::insert(*Te_ifBoolTemp);
	 delete UniBool;
	 delete BiBool;
	 delete Ty_ifBool;
	 delete Te_ifBoolTemp;	

	ArrowType* Ty_ifNumber = new ArrowType(*Ty_Boolean, *Arity2Function);
	FreeTermVariable* Te_ifNumberTemp = new FreeTermVariable (*Ty_ifNumber, "ifNumber");	
	Te_ifNumber = EvaluatingTermSet::insert(*Te_ifNumberTemp);
	delete Ty_ifNumber;
	delete Te_ifNumberTemp;

	}






void NoAbstractionGeneSet::initBooleanOperators( void ){
	 ArrowType*  UniBool		= new ArrowType(*Ty_Boolean, *Ty_Boolean);
	 ArrowType*  BiBool			= new ArrowType(*Ty_Boolean, *UniBool);
	 
	 FreeTermVariable* Te_AndTemp = new FreeTermVariable(*BiBool, "And");	
	 Te_And = TermSet::insert( *Te_AndTemp );
	 Primitives.push_back(Te_And);

	 FreeTermVariable* Te_OrTemp = new FreeTermVariable(*BiBool, "Or");	
	 Te_Or = TermSet::insert( *Te_OrTemp );
	 Primitives.push_back(Te_Or);

	 FreeTermVariable* Te_NotTemp = new FreeTermVariable(*UniBool, "Not");	
	 Te_Not = TermSet::insert( *Te_NotTemp );
	 Primitives.push_back(Te_Not);

	 delete Te_NotTemp;
	 delete Te_OrTemp;
	 delete Te_AndTemp;
	 delete UniBool;
	 delete BiBool;
	}

void LTAbstractionGeneSet::initBaseTypes( void ){
	insert(*(Ty_Number   = new FreeTypeVariable("D")));
	FreeTypeVariable* TempType = new FreeTypeVariable("X");

	insert(*(Ty_Boolean = new AbstractType(
					ArrowType(*TempType, ArrowType(*TempType,*TempType)), 
					*TempType, 
					"Boolean")));
	delete TempType;
	}

void LTAbstractionGeneSet::initBooleans( void ){
	FreeTypeVariable* Ty_Temp =new FreeTypeVariable("X");
	FreeTermVariable* Ter_Temp =new FreeTermVariable(*Ty_Temp,"o");

	AbstractTypeTerm* Te_TrueTemp = new AbstractTypeTerm (
				AbstractTerm(AbstractTerm(*Ter_Temp, FreeTermVariable(*Ty_Temp)), *Ter_Temp), 
				*Ty_Temp,
				"True");	

	Te_TrueTemp->setTypeSyntax(Ty_Boolean->getSyntax());
	Te_True = insert(*(Te_TrueTemp));
	this->setAsPrimitive( *Te_True );
	SemanticEvaluation SET;
	SET.first = Te_TrueTemp->clone( );
	setValue( Te_True, SET ); 
	delete Te_TrueTemp;

	AbstractTypeTerm* Te_FalseTemp = new AbstractTypeTerm (
				AbstractTerm(AbstractTerm(*Ter_Temp,*Ter_Temp),*Ter_Temp),
				*Ty_Temp,
				"False");

	Te_FalseTemp->setTypeSyntax(Ty_Boolean->getSyntax());
	Te_False = insert(*(Te_FalseTemp));
	this->setAsPrimitive( *Te_False );
	SemanticEvaluation SEF;
	SEF.first = Te_FalseTemp->clone( );
	setValue( Te_False, SEF ); 
	delete Te_FalseTemp;


	delete Ty_Temp;
	delete Ter_Temp;
	}

void LAbstractionGeneSet::initBooleans( void ){


	}



void LAbstractionGeneSet::initBooleanOperators( void ){
	FreeTermVariable* x1 = new FreeTermVariable(*Ty_Boolean);
	FreeTermVariable* x2 = new FreeTermVariable(*Ty_Boolean);
	/*
	ApplicationTerm Temp1(ApplicationTerm(ApplicationTerm(*x1, *Ty_Boolean), *x2), *Te_False);	
	Te_And = new AbstractTerm(AbstractTerm(Temp1, *x2), *x1, "And");
	insert(*Te_And);
	   
	ApplicationTerm Temp2(ApplicationTerm(ApplicationTerm(*x1, *Ty_Boolean), *Te_False), *Te_True);
	Te_Not = new AbstractTerm(Temp2, *x1, "Not");
	insert(*Te_Not);

	 ApplicationTerm Temp3(ApplicationTerm(ApplicationTerm(*x1,  *Ty_Boolean), *Te_True) , *x2);
	 Te_Or = new AbstractTerm(AbstractTerm(Temp3, *x2), *x1, "Or");
	 insert(*Te_Or);	*/

	 delete x1;
	 delete x2;
	}












